#include <iostream>
#include <random>
#include <vector>
#include <chrono>
#include <cstring>
#include "mltree/index/mltree.hpp"
#include "mltree/entities/points.hpp"
#include "mltree/common/FileIO.hpp"

using namespace std;
using namespace MetricSpaceBenchmark::MLIndex::MLTree;

static mt19937_64 m_gen(100ULL);
static uniform_real_distribution<double> m_distrib(0.0, 1.0);

constexpr size_t KEY_LENGTH = 10;

class KeyObject {
public:
    std::vector <DIS_TYPE> key;

    KeyObject() : key(KEY_LENGTH, static_cast<DIS_TYPE>(0.0)) {}

    explicit KeyObject(const double keyArr[]) {
        key.assign(keyArr, keyArr + KEY_LENGTH);
    }

    KeyObject(const KeyObject &other) {
        key = other.key;
    }

    KeyObject &operator=(const KeyObject &other) {
        if (this != &other) {
            key = other.key;
        }
        return *this;
    }

    // 移动构造函数
    KeyObject(KeyObject &&other) noexcept: key(std::move(other.key)) {}

    // 移动赋值运算符
    KeyObject &operator=(KeyObject &&other) noexcept {
        if (this != &other) {
            key = std::move(other.key);
        }
        return *this;
    }

    bool operator==(const KeyObject &other) const {
        return key == other.key;
    }

    // 使用标准算法优化 distance()
    [[nodiscard]] DIS_TYPE distance(const KeyObject &other) const {
        return std::sqrt(std::transform_reduce(
                key.begin(), key.end(), other.key.begin(), DIS_TYPE{0}, std::plus<>(),
                [](DIS_TYPE a, DIS_TYPE b) {
                    const DIS_TYPE diff = a - b;
                    return diff * diff;
                }
        ));
    }

    // 添加迭代器函数
    typename std::vector<DIS_TYPE>::iterator begin() { return key.begin(); }

    typename std::vector<DIS_TYPE>::iterator end() { return key.end(); }

    // 添加常量迭代器函数
    [[nodiscard]] typename std::vector<DIS_TYPE>::const_iterator begin() const { return key.begin(); }

    [[nodiscard]] typename std::vector<DIS_TYPE>::const_iterator end() const { return key.end(); }

    // 哈希函数
    friend std::size_t hash_value(const KeyObject &obj) {
        std::size_t seed = obj.key.size();
        for (const auto &val: obj.key) {
            // 确保 val 的类型大小与 uint64_t 一致
            static_assert(sizeof(val) == sizeof(uint64_t), "Type size mismatch for bitwise cast");

            uint64_t val_bits;
            std::memcpy(&val_bits, &val, sizeof(uint64_t));

            seed ^= std::hash < uint64_t > {}(val_bits) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        }
        return seed;
    }
//    friend std::size_t hash_value(const KeyObject &obj) {
//        std::size_t seed = obj.key.size();
//        for (const auto &val: obj.key) {
//            const auto val_bits = std::bit_cast<uint64_t>(val);
//            seed ^= std::hash<uint64_t>{}(val_bits) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
//        }
//        return seed;
//    }
};

namespace std {
    template<>
    struct hash<KeyObject> {
        std::size_t operator()(const KeyObject &obj) const {
            return hash_value(obj);
        }
    };
}

void generate_center(double center[]) {
    for (size_t i = 0; i < KEY_LENGTH; i++) {
        center[i] = m_distrib(m_gen);
    }
}

uint32_t generate_data(vector <Point<KeyObject>> &entries, const size_t N) {
    double buf[KEY_LENGTH];
    for (size_t i = 0; i < N; i++) {
        generate_center(buf);
        entries.emplace_back(i, KeyObject(buf));
    }
    return entries.size();
}

int main() {
    std::chrono::steady_clock::time_point time_begin;
    std::chrono::steady_clock::time_point time_end;

    string filename_main = "../../results/mltree/main_out.txt";
    std::ofstream outFile(filename_main, std::ios::app);
    if (outFile.is_open()) {
        outFile << "*******************************Start************************************" << std::endl;
        string filename_base_dataset = "../../dataset/";
//        string filename_fft_id = filename_base_dataset + "points_fft_id.txt";
//        string filename_fft_noId = filename_base_dataset + "points_fft.txt";
//        string filename_original = filename_base_dataset + "points_original.txt";

        string filename_fft_id = filename_base_dataset + "forest_fft_id_100000.txt";
        string filename_fft_noId = filename_base_dataset + "forest_fft_100000.txt";
        string filename_original = filename_base_dataset + "forest_original_100000.txt";

        outFile << "Add Points: " << std::endl;
        std::vector<Point<KeyObject>> entries;
        ReadDataFromFileWithID<KeyObject>(filename_fft_id, entries);
        outFile << "Point Size: " << entries.size() << ", Add Points Over " << std::endl;

        unsigned long M = 30;
        auto MLTreePtr = std::make_unique<MLTree<KeyObject>>();
        time_begin = std::chrono::steady_clock::now();
        MLTreePtr->buildMLTree(entries, M);
        time_end = std::chrono::steady_clock::now();

        outFile << "build time:" << std::chrono::duration_cast<std::chrono::milliseconds>(time_end - time_begin).count()
                << " [µs]" << std::endl;
        outFile << "************************************************************************" << std::endl;

        // 生成查询点
        std::vector<Point<KeyObject>> list_rangeQry;
//        string query_filename = filename_base_dataset + "query_points.txt";
        string query_filename = filename_base_dataset + "query_forest.txt";
        ReadDataFromFile_Query(query_filename, list_rangeQry);

        // 查询半径
        DIS_TYPE queryRadius = 0.2;
        // 查询平均时间
        unsigned long time = 0.0;

        // 存储查询结果
        std::vector<Point<KeyObject>> result;

        for (auto &queryPoint: list_rangeQry) {       // 遍历每个查询点
            // 执行范围查询
            result.clear();
            time_begin = std::chrono::steady_clock::now();
            MLTreePtr->rangeQuery(queryPoint, queryRadius, result);
            time_end = chrono::steady_clock::now();
            time += chrono::duration_cast<chrono::microseconds>(time_end - time_begin).count();
            // 输出查询结果
            outFile << "该轮范围查询结果数:" << result.size() << ", 执行耗时: "
                    << chrono::duration_cast<chrono::microseconds>(time_end - time_begin).count() << " [µs]"
                    << std::endl;
        }
        outFile << "************************************************************************" << std::endl;
        time /= list_rangeQry.size();
        outFile << "range query avg time is : " << time << " [µs]" << std::endl;
        outFile << "************************************************************************" << std::endl;
        size_t count = 0;
        MLTreePtr->printTree(count);
        outFile << "叶节点存储的数据量: " << count << std::endl;
        outFile << "************************************************************************" << std::endl;
        outFile << "********************************Over************************************" << std::endl << std::endl;
    }

    return 0;
}